package valuecomusa.fijibus.eticket.BitmapUtils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: fireman
 * Date: 6/24/13
 * Time: 11:27 PM
 * To change this template use File | Settings | File Templates.
 */
public class BitmapHelper
{
    private final String TAG = "BitmapHelper";

    public static byte[] getBytes(int value)
    {
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        DataOutputStream stream = new DataOutputStream(byteStream);
        try
        {
            stream.writeInt(value);
        }
        catch (IOException e)
        {
            return new byte[4];
        }
        return byteStream.toByteArray();
    }

    public BitmapData getBitmapData(String bmpFileName)
    {
        Bitmap bitmap = BitmapFactory.decodeFile(bmpFileName);

        int threshold = 127;
        int index = 0;
        int xHeight = bitmap.getHeight();
        int xWidth = bitmap.getWidth();
        //int dimensions = xWidth * xHeight;
        byte[][] dots = new byte[xHeight][xWidth];

        for (int y = 0; y < xHeight; y++)
        {
            for (int x = 0; x < xWidth; x++)
            {
                int color = bitmap.getPixel(x, y);
                int red = (color & 0x00ff0000) >> 16;
                int green = (color & 0x0000ff00) >> 8;
                int blue = color & 0x000000ff;
                int luminance = (int) (red * 0.3 + green * 0.59 + blue * 0.11);
                if(luminance < threshold)
                    dots[y][x] = 1;
                else
                    dots[y][x] = 0;
            }
        }

        BitmapData data = new BitmapData();

        data.Dots = dots;
        data.Height = bitmap.getHeight();
        data.Width = bitmap.getWidth();

        return data;
    }

    public List<byte[]> printPicture(BitmapData data) throws IOException
    {
        if(data == null)
            return null;

        List<byte[]> resultSegments = new ArrayList<byte[]>();

        byte[][] dots = data.Dots;
        try
        {

            //ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            //outputStream.write(PrinterCommands.INIT);
            //printerConnection.sndByte(PrinterCommands.INIT);

            // So we have our bitmap data sitting in a bit array called "dots."
            // This is one long array of 1s (black) and 0s (white) pixels arranged
            // as if we had scanned the bitmap from top to bottom, left to right.
            // The printer wants to see these arranged in bytes stacked three high.
            // So, essentially, we need to read 24 bits for x = 0, generate those
            // bytes, and send them to the printer, then keep increasing x. If our
            // image is more than 24 dots high, we have to send a second bit image
            // command to draw the next slice of 24 dots in the image.
            // Set the line spacing to 24 dots, the height of each "stripe" of the
            // image that we're drawing. If we don't do this, and we need to
            // draw the bitmap in multiple passes, then we'll end up with some
            // whitespace between slices of the image since the default line
            // height--how much the printer moves on a newline--is 30 dots.

            //outputStream.write(PrinterCommands.SET_LINE_SPACING_24);
            //printerConnection.sndByte(PrinterCommands.SET_LINE_SPACING_24);

            // OK. So, starting from x = 0, read 24 bits down and send that data
            // to the printer. The offset variable keeps track of our global 'y'
            // position in the image. For example, if we were drawing a bitmap
            // that is 48 pixels high, then this while loop will execute twice,
            // once for each pass of 24 dots. On the first pass, the offset is
            // 0, and on the second pass, the offset is 24. We keep making
            // these 24-dot stripes until we've execute past the height of the
            // bitmap.
            int rowIdx = 0;

            byte[] width = BitmapHelper.getBytes(data.Width);
            byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, width[3], width[2]};
            //printerConnection.sndByte(SELECT_BIT_IMAGE_MODE);
            //outputStream.write(SELECT_BIT_IMAGE_MODE);
            while (rowIdx < data.Height)
            {
                // The third and fourth parameters to the bit image command are
                // 'nL' and 'nH'. The 'L' and the 'H' refer to 'low' and 'high', respectively.
                // All 'n' really is is the width of the image that we're about to draw.
                // Since the width can be greater than 255 dots, the parameter has to
                // be split across two bytes, which is why the documentation says the
                // width is 'nL' + ('nH' * 256).

                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                outputStream.write(SELECT_BIT_IMAGE_MODE);
                //printerConnection.sndByte(SELECT_BIT_IMAGE_MODE);

                for (int x = 0; x < data.Width; ++x)
                {
                    // Remember, 24 dots = 24 bits = 3 bytes.
                    // The 'k' variable keeps track of which of those
                    // three bytes that we're currently scribbling into.
                    //int k=0;
                    for (int k = 0; k < 3; ++k)
                    {
                        byte slice = 0;
                        // A byte is 8 bits. The 'b' variable keeps track
                        // of which bit in the byte we're recording.
                        for (int b = 0; b < 8; ++b)
                        {
                            // Calculate the y position that we're currently
                            // trying to draw. We take our offset, divide it
                            // by 8 so we're talking about the y offset in
                            // terms of bytes, add our current 'k' byte
                            // offset to that, multiple by 8 to get it in terms
                            // of bits again, and add our bit offset to it.
                            int y = rowIdx + k*8 + b; //   (((rowIdx / 8) + k) * 8) + b;
                            // Calculate the location of the pixel we want in the bit array.
                            // It'll be at (y * width) + x.
                            //int i = (y * data.Width) + x;
                            // If the image (or this stripe of the image)
                            // is shorter than 24 dots, pad with zero.
                            /*boolean v = false;
                            if (i < dots.size())
                            {
                                v = dots.get(i);
                            }*/
                            byte value = 0;
                            if(y < data.Height)
                                value = dots[y][x];
                            // Finally, store our bit in the byte that we're currently
                            // scribbling to. Our current 'b' is actually the exact
                            // opposite of where we want it to be in the byte, so
                            // subtract it from 7, shift our bit into place in a temp
                            // byte, and OR it with the target byte to get it into there.
                            slice |= (byte) (value << (7 - b));
                        }
                        // Phew! Write the damn byte to the buffer
                        outputStream.write(slice);
                    }
                }
                // We're done with this 24-dot high pass. Render a newline
                // to bump the print head down to the next line
                // and keep on trucking.
                rowIdx += 24;
                //rowIdx += 8;
                //outputStream.write(PrinterCommands.FEED_LINE);
                outputStream.write(0x1B);
                outputStream.write(0x4A);
                outputStream.write(24); //print and feed
                //--
                byte[] xContent = outputStream.toByteArray();
                outputStream.close();
                //--
                resultSegments.add(xContent);
                //printerConnection.sndByte(SELECT_BIT_IMAGE_MODE);
                //printerConnection.sndByte(xContent);

                //Thread.sleep(300);

            }
            // Restore the line spacing to the default of 30 dots.
            //outputStream.write(PrinterCommands.SET_LINE_SPACING_30);
            //printerConnection.sndByte(PrinterCommands.SET_LINE_SPACING_30);

            /*byte[] xContent = outputStream.toByteArray();
            outputStream.close();
            //--
            printerConnection.sndByte(xContent);*/
        }
        catch (Exception ex)
        {
            Log.e(TAG, ex.getMessage());
        }
        return resultSegments;
    }

}
